﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using QFramework;
using System.IO;
using System.Text;
using ICSharpCode.SharpZipLib.Zip;
using System.Threading;
using System.Net;

namespace CreatPart
{
    public class WebReadAndDownLoad
    {
        private static WebReadAndDownLoad mInstance;
        public static WebReadAndDownLoad Instance
        {
            get
            {
                if (mInstance != null) { return mInstance; }
                else { mInstance = new WebReadAndDownLoad(); return mInstance; }
            }
        }

        private WebReadAndDownLoad() { }

        #region inquire&download

        public static string event1 = "event1";
        public static string event2 = "event2";
        public static EasyThread easyThread = EasyThread.GetInstance();
        public ThreadDownLoad threadDownLoad;

        //得到局域网的配置文件
        public IEnumerator GetVersionConfigByWeb(string url, Action<WebConfigData> action)
        {
            UnityWebRequest web = UnityWebRequest.Get(url);

            yield return web.SendWebRequest();
            if (web.downloadHandler.isDone)
            {
                if (web.isHttpError || web.isHttpError)
                {
                    Debug.LogError("读取服务器版本信息错误!");
                }
                else
                {
                    action(JsonUtility.FromJson<WebConfigData>(web.downloadHandler.text));
                }
            }
        }

        //线程中下载一个压缩文件
        public void DownLoadZipAssetThread(string downloadPath, string fileName, string savePath, Action<float> LoadProgress, Action DownLoadSuccess, Action CompressCussecc)
        {
            threadDownLoad = new ThreadDownLoad(downloadPath, fileName, savePath, LoadProgress, DownLoadSuccess, CompressCussecc);
            threadDownLoad.StartThread();

            MainThreadMonitor(threadDownLoad);
        }
      
        //线程中下载多个压缩文件
        public void DownLoadAllZipAssetByWeb(string downloadPath, string savePath, Action<float, int, int> LoadProgress, Action DownLoadSuccess, Action CompressCussecc)
        {
            threadDownLoad = new ThreadDownLoad(downloadPath, savePath, this, LoadProgress, DownLoadSuccess, CompressCussecc);
            threadDownLoad.StartDownloadAllThread();

            MainThreadMonitor(threadDownLoad);
        }

        //线程中更新资源包
        public void UpdateAssetsPackage(string downloadPath,string[] needUpdateZipArray,string savePath,Action<float,int,int> LoadProgress,Action DownLoadSuccess,Action CompressCussecc)
        {
            threadDownLoad = new ThreadDownLoad(downloadPath, savePath, this, LoadProgress, DownLoadSuccess, CompressCussecc);
            threadDownLoad.needUpdateZipArray = needUpdateZipArray;
            threadDownLoad.StartUpdateAssetsThread();

            MainThreadMonitor(threadDownLoad);
        }

        //主线程中监听线程中的事件，来传递消息
        void MainThreadMonitor(ThreadDownLoad tdl)
        {
            //主线程启动监听 ，监听的标志String是event1
            easyThread.mainRemote.On(event1, () =>
            {
                //这个类让没有继承Mono的类能使用协程方法，这里是启动了一个监听线程下载完成的协程
                MonoMgr.Instance.StartCoroutine(tdl.MonitorThreadStop());

                //完成后移除掉这个监听
                easyThread.mainRemote.Remove(event1);
            }); 
        }

        //线程下载的类
        public class ThreadDownLoad
        {
            private string DownLoadPath;
            private string FileName;
            private string SavePath;
            private Thread thread;
            private Action<float> LoadProgress;
            private Action DownLoadSuccess;
            private Action CompressSuccess;
            private Action CompressAllSuccess;

            private Action<float, int, int> LoadAllProgress;
            private WebReadAndDownLoad mWebReadAndDownLoad;

            private List<string> folderVessel = new List<string>();
            private List<string> fileVessel = new List<string>();
            private List<string> packageVessel = new List<string>();

            bool isThreadState;  //线程的状态，由于所有的下载都只启动一个线程，所以只有一个bool来判断，多线程可以参考  https://gitee.com/fancaihua/multiple-thread-demo.git
            bool isForceStop;
            string saveWholePath;

            public string[] needUpdateZipArray; 

            public ThreadDownLoad(string downLoadPath, string fileName, string savePath, Action<float> loadProgress, Action DownLoadSuccess, Action CompressSuccess)
            {
                DownLoadPath = downLoadPath;
                FileName = fileName;
                SavePath = savePath;
                LoadProgress = loadProgress;
                this.DownLoadSuccess = DownLoadSuccess;
                this.CompressSuccess = CompressSuccess;
            }

            public ThreadDownLoad(string downLoadPath, string savePath, WebReadAndDownLoad wtd, Action<float, int, int> loadProgress, Action DownLoadSuccess, Action CompressSuccess)
            {
                mWebReadAndDownLoad = wtd;
                DownLoadPath = downLoadPath;
                SavePath = savePath;
                LoadAllProgress = loadProgress;
                this.DownLoadSuccess = DownLoadSuccess;
                this.CompressAllSuccess = CompressSuccess;
            }

            //开始线程
            public void StartThread()
            {
                saveWholePath = SavePath + "/" + FileName;

                thread = new Thread(new ThreadStart(ExecuteThread));
                thread.IsBackground = true;
                thread.Start();

                isThreadState = false;

                InitMonitorEvent();
            }

            public void StartDownloadAllThread()
            {
                thread = new Thread(new ThreadStart(ExecuteThreadDownloadAll));
                thread.IsBackground = true;
                thread.Start();

                isThreadState = false;

                InitMonitorEvent();
            }

            public void StartUpdateAssetsThread()
            {
                thread = new Thread(new ThreadStart(ExecuteThreadUpdateAssets));
                thread.IsBackground = true;
                thread.Start();

                isThreadState = false;

                InitMonitorEvent();
            }

            //监听事件
            private void InitMonitorEvent()
            {
                //这里做一个注册
                easyThread.childRemote.Once(event2, () =>
                {
                    easyThread.mainRemote.Send(event1);
                });

                //这里来启动之前的注册  Tips:原本只需要执行Send(event1)就可以，这里做演示。开始注册，能注册多种事件，然后能在其他地方执行
                easyThread.childRemote.Send(event2);
            }
          
            //执行下载
            private void ExecuteThread()
            {
                Debug.Log("开始线程");

                if (!Directory.Exists(SavePath))
                {
                    Directory.CreateDirectory(SavePath);
                }

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(DownLoadPath + "/" + FileName);

                request.Method = "GET";

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            
                Stream stream = response.GetResponseStream();
               
                FileStream fileStream = File.Create(saveWholePath);

                int wholeLength = (int)response.ContentLength;

                byte[] buffer = new byte[10240];
                int bytesRead = 0;
                float progress = 0;

                int curWholeReadCount = 0;

                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    curWholeReadCount += bytesRead;

                    fileStream.Write(buffer, 0, bytesRead);

                    progress = curWholeReadCount / (float)wholeLength;

                    LoadProgress(progress);

                    if (isForceStop)
                    {
                        break;
                    }
                }

                fileStream.Close();
                stream.Close();
                response.Close();

                if (DownLoadSuccess != null)
                    DownLoadSuccess();

                Debug.Log("开始解压");

                FileStream compressStream = new FileStream(saveWholePath, FileMode.Open);
                DecompressToDirectory(compressStream, SavePath);

                //删除压缩包
                FileInfo info = new FileInfo(saveWholePath);
                info.Delete();
            }

            //执行下载所有
            private void ExecuteThreadDownloadAll()
            {
                if (!Directory.Exists(SavePath))
                {
                    Directory.CreateDirectory(SavePath);
                }

                Debug.Log("进入下载的路径:" + DownLoadPath);
                Debug.Log("进入安装的路径:" + SavePath);


                string directoryDownloadPath = mWebReadAndDownLoad.ToDirectoryUrl(DownLoadPath);

                Debug.Log("查询文件夹的路径:" + directoryDownloadPath);

                GetSourceFolder(directoryDownloadPath);

                Debug.Log("文件的数量:" + fileVessel.Count);

                int allFileCount = fileVessel.Count;
                int currentDownloadCount = 0;
                int wholeLength = 0;

                for (int i = 0; i < folderVessel.Count; i++)
                {
                    string tp = folderVessel[i].Replace(directoryDownloadPath, SavePath);
                    Directory.CreateDirectory(tp);
                }


                HttpWebRequest request;
                HttpWebResponse response;
                Stream stream;
                FileStream fileStream;

                for (int i = 0; i < fileVessel.Count; i++)
                {
                    currentDownloadCount = i + 1;


                    string newSaveUrl = fileVessel[i].Replace(directoryDownloadPath, SavePath);
                    string newDownloadUrl = mWebReadAndDownLoad.ToWebRequestUrl(fileVessel[i]);

                    packageVessel.Add(newSaveUrl);

                    Debug.Log("下载的路径:" + newDownloadUrl);
                    Debug.Log("安装的路径:" + newSaveUrl);

                    request = (HttpWebRequest)WebRequest.Create(newDownloadUrl);
                    request.Method = "GET";
                    response = (HttpWebResponse)request.GetResponse();
                    stream = response.GetResponseStream();
                    fileStream = File.Create(newSaveUrl);


                    byte[] buffer = new byte[10240];
                    int bytesRead = 0;
                    float progress = 0;

                    wholeLength = (int)response.ContentLength;
                    int curWholeReadCount = 0;

                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        curWholeReadCount += bytesRead;

                        fileStream.Write(buffer, 0, bytesRead);

                        progress = curWholeReadCount / (float)wholeLength;

                        LoadAllProgress(progress, currentDownloadCount, allFileCount);

                        if (isForceStop)
                        {
                            break;
                        }
                    }

                    fileStream.Close();
                    stream.Close();
                    response.Close();
                }

                if (DownLoadSuccess != null)
                    DownLoadSuccess();

                for (int i = 0; i < packageVessel.Count; i++)
                {
                    FileStream zipFileStream = new FileStream(packageVessel[i], FileMode.Open);   //在线程中下载必须带上FileMode.Open

                    DecompressAllToDirectory(zipFileStream, SavePath, i == packageVessel.Count - 1);

                    FileInfo info = new FileInfo(packageVessel[i]);
                    info.Delete();
                }
            }

            //执行更新
            private void ExecuteThreadUpdateAssets()
            {
                if (!Directory.Exists(SavePath))
                {
                    Directory.CreateDirectory(SavePath);
                }

                Debug.Log("进入下载的路径:" + DownLoadPath);
                Debug.Log("进入安装的路径:" + SavePath);


                string directoryDownloadPath = mWebReadAndDownLoad.ToDirectoryUrl(DownLoadPath);

                Debug.Log("查询文件夹的路径:" + directoryDownloadPath);

                GetSourceFolder(directoryDownloadPath);

                Debug.Log("文件的数量:" + fileVessel.Count);

                int allFileCount = fileVessel.Count;
                int currentDownloadCount = 0;
                int wholeLength = 0;

                for (int i = 0; i < folderVessel.Count; i++)
                {
                    string tp = folderVessel[i].Replace(directoryDownloadPath, SavePath);
                    Directory.CreateDirectory(tp);
                }


                ConfirmFileVessel(needUpdateZipArray);

                HttpWebRequest request;
                HttpWebResponse response;
                Stream stream;
                FileStream fileStream;

                for (int i = 0; i < fileVessel.Count; i++)
                {
                    currentDownloadCount = i + 1;

                    string newSaveUrl = fileVessel[i].Replace(directoryDownloadPath, SavePath);
                    string newDownloadUrl = mWebReadAndDownLoad.ToWebRequestUrl(fileVessel[i]);

                    packageVessel.Add(newSaveUrl);

                    Debug.Log("下载的路径:" + newDownloadUrl);
                    Debug.Log("安装的路径:" + newSaveUrl);

                    string updateDir = newSaveUrl.Substring(0, newSaveUrl.Length - 4);

                    if (Directory.Exists(updateDir))
                    {
                        Directory.Delete(updateDir,true);
                    }

                    request = (HttpWebRequest)WebRequest.Create(newDownloadUrl);
                    request.Method = "GET";
                    response = (HttpWebResponse)request.GetResponse();
                    stream = response.GetResponseStream();
                    fileStream = File.Create(newSaveUrl);


                    byte[] buffer = new byte[10240];
                    int bytesRead = 0;
                    float progress = 0;

                    wholeLength = (int)response.ContentLength;
                    int curWholeReadCount = 0;

                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        curWholeReadCount += bytesRead;

                        fileStream.Write(buffer, 0, bytesRead);

                        progress = curWholeReadCount / (float)wholeLength;

                        LoadAllProgress(progress, currentDownloadCount, allFileCount);

                        if (isForceStop)
                        {
                            break;
                        }
                    }

                    fileStream.Close();
                    stream.Close();
                    response.Close();
                }

                if (DownLoadSuccess != null)
                    DownLoadSuccess();

                for (int i = 0; i < packageVessel.Count; i++)
                {
                    FileStream zipFileStream = new FileStream(packageVessel[i], FileMode.Open);

                    DecompressAllToDirectory(zipFileStream, SavePath, i == packageVessel.Count - 1);

                    FileInfo info = new FileInfo(packageVessel[i]);
                    info.Delete();
                }
            }


            private void StopThread()
            {
                thread.Abort();

                if (CompressSuccess != null)
                {
                    CompressSuccess();
                }

                if (CompressAllSuccess != null)
                {
                    CompressAllSuccess();
                }
            }

            public IEnumerator MonitorThreadStop()
            {
                while (true)
                {
                    if (isThreadState)
                    {
                        break;
                    }
                    yield return 0;
                }

                StopThread();
            }

            private void DecompressToDirectory(Stream source, string targetPath)
            {
                Decompress(source, targetPath);

                Debug.Log("解压完成");

                isThreadState = true;
            }

            private void DecompressAllToDirectory(Stream source, string targetPath, bool isCompressSuccess)
            {
                Decompress(source, targetPath);

                Debug.Log("解压完成");

                if (isCompressSuccess)
                {
                    isThreadState = true;
                }
            }

            //解压
            private void Decompress(Stream source, string targetPath)
            {
                targetPath = Path.GetFullPath(targetPath);
                using (ZipInputStream decompressor = new ZipInputStream(source))
                {
                    ZipEntry entry;

                    while ((entry = decompressor.GetNextEntry()) != null)
                    {
                        entry.IsUnicodeText = true;

                        string name = entry.Name;
                        if (entry.IsDirectory && entry.Name.StartsWith("\\"))
                            name = entry.Name.Replace("\\", "");

                        string filePath = Path.Combine(targetPath, name);
                        string directoryPath = Path.GetDirectoryName(filePath);

                        if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
                            Directory.CreateDirectory(directoryPath);

                        if (entry.IsDirectory)
                            continue;

                        byte[] data = new byte[2048];
                        using (FileStream streamWriter = File.Create(filePath))
                        {
                            int bytesRead;
                            while ((bytesRead = decompressor.Read(data, 0, data.Length)) > 0)
                            {
                                streamWriter.Write(data, 0, bytesRead);

                            }
                        }
                    }
                }
            }

            public void ForceStopThread()
            {
                isForceStop = true;
                thread.Abort();
            }

            //得到路径下所有的文件夹
            void GetLocalSourceFolder(string folder)
            {
                GetLocalSourceFile(folder);
                string[] _dir = Directory.GetDirectories(folder);
                for (int i = 0; i < _dir.Length; i++)
                {
                    folderVessel.Add(_dir[i]);
                    GetLocalSourceFolder(_dir[i]);
                }
            }

            //得到路径下所有的文件
            void GetLocalSourceFile(string path)
            {
                string[] files = Directory.GetFiles(path);
                for (int i = 0; i < files.Length; i++)
                {
                    fileVessel.Add(files[i]);
                }
            }

            void GetSourceFolder(string folder)
            {
                GetSourceFile(folder);
                DirectoryInfo di = new DirectoryInfo(folder);
                foreach (DirectoryInfo subDir in di.GetDirectories())
                {
                    string newFloder = folder + "/" + subDir.Name;
                    folderVessel.Add(newFloder);
                    GetSourceFolder(newFloder);
                }
            }

            void GetSourceFile(string path)
            {
                string newString = null;

                foreach (string subDir in Directory.GetFiles(path))
                {
                    newString = subDir.Replace('\\', '/');
                    fileVessel.Add(newString);
                }
            }

            //只处理需要更新的文件夹
            void ConfirmFileVessel(string[] updateArray)
            {
                List<string> tempList = new List<string>();

                for (int i = 0; i < updateArray.Length; i++)
                {
                    for (int j = 0; j < fileVessel.Count; j++)
                    {
                        if (GetFileName(fileVessel[j]).Contains(updateArray[i]))
                        {
                            tempList.Add(fileVessel[j]);
                            break;
                        }
                    }
                }


                fileVessel.Clear();

                tempList.ForEach(item => { fileVessel.Add(item); });
            }

            string GetFileName( string url)
            {
                int index = url.LastIndexOf('/') +1;
                url = url.Substring(index,url.Length - index);
                return url; 
            }
        }

        #endregion



        #region url change

        //路径这里需要注意，如果是下载 可以使用http：+ 带端口号  ，或者使用本地下载file：不需要端口号
        //如果是查询局域网文件夹，或者在本地下载新建文件夹，是不需要http和端口号，也不需要file的
        //另外 \ 很容易出bug，最好修改成 /


        string ToDirectoryUrl(string url)
        {
            return url.Replace('\\', '/').Replace("http:", "").Replace(":90", "");
        }

        string ToWebRequestUrl(string url)
        {
            //http://192.168.21.200:90/UnityAssets/CreatParty/Install
            //@"//192.168.21.200/UnityAssets/CreatParty";
            return "http:" + url.Replace("200", "200:90");
        }



        #endregion

        #region discard method 

        public IEnumerator DownLoadAssetByWeb(string downloadPath, string filename, string savePath, Action DownLoad = null)
        {
            string originPath = downloadPath + "/" + filename;

            using (UnityWebRequest request = UnityWebRequest.Get(originPath))
            {

                Debug.Log(savePath);

                yield return request.SendWebRequest();

                if (request.isDone)
                {
                    Debug.Log("isDone");

                    byte[] results = request.downloadHandler.data;

                    Debug.Log(savePath);

                    if (!Directory.Exists(savePath))
                    {
                        Directory.CreateDirectory(savePath);
                    }

                    FileInfo fileInfo = new FileInfo(savePath + "/" + filename);
                    FileStream fs = fileInfo.Create();
                    fs.Write(results, 0, results.Length);
                    fs.Flush(); 
                    fs.Close(); 
                    fs.Dispose(); 
                    if (DownLoad != null)
                        DownLoad();

                }
            }
        }

        public IEnumerator DownLoadAllAssetByWeb(string downloadPath, string savePath, Action<int, int> LoadProgress, Action DownLoad = null)
        {
            //if (!Directory.Exists(savePath))
            //{
            //    Directory.CreateDirectory(savePath);
            //}

            ////修改文件路径名称
            //downloadPath = ToDirectoryUrl(downloadPath);

            //Debug.Log(downloadPath);

            ////得到所有的文件件路径和所有文件的路径
            //getSourceFolder(downloadPath);

            //Debug.Log("文件的数量:" + fileVessel.Count);

            //int allFileCount = fileVessel.Count;
            //int currentDownloadCount = 0;

            //for (int i = 0; i < folderVessel.Count; i++)
            //{
            //    string tp = folderVessel[i].Replace(downloadPath, savePath);
            //    Directory.CreateDirectory(tp);
            //}

            //for (int i = 0; i < fileVessel.Count; i++)
            //{
            //    currentDownloadCount = i;

            //    string installUrl = fileVessel[i].Replace(downloadPath, savePath);

            //    Debug.Log("加载的路径:" + fileVessel[i]); //
            //    Debug.Log("安装的路径:" + installUrl);  //

            //    UnityWebRequest request = UnityWebRequest.Get(fileVessel[i]);

            //    yield return request.SendWebRequest();

            //    if (request.isNetworkError || request.isHttpError)
            //    {
            //        Debug.Log("Download Error:" + request.error);
            //    }
            //    else if (request.isDone)
            //    {
            //        byte[] results = request.downloadHandler.data;

            //        Debug.Log("资源长度:" + results.Length);  //长度都是相同的

            //        FileInfo fileInfo = new FileInfo(installUrl);
            //        FileStream fs = fileInfo.Create();

            //        //FileStream fs = new FileStream(installUrl, FileMode.Create);

            //        //fs.Write(字节数组, 开始位置, 数据长度);
            //        fs.Write(results, 0, results.Length);
            //        fs.Flush(); //文件写入存储到硬盘
            //        fs.Close(); //关闭文件流对象
            //        fs.Dispose(); //销毁文件对象
            //    }

            //    if (LoadProgress != null)
            //    {
            //        LoadProgress(currentDownloadCount, allFileCount);
            //    }

            //    request.Dispose();
            //}

            yield return 0;


            //if (DownLoad != null)
            //    DownLoad();
        }


        /// <summary>
        /// 压缩文件下载并解压
        /// </summary>
        /// <param name="downloadPath">下载路径</param>
        /// <param name="fileName">文件名</param>
        /// <param name="savePath">保存路径</param>
        /// <param name="LoadProgress">下载进度回调</param>
        /// <param name="DownLoad">完成回调</param>
        /// <returns></returns>
        public IEnumerator DownLoadZipAssetByWeb(string downloadPath, string fileName, string savePath, Action<UnityWebRequest> LoadProgress, Action DownLoad)
        {
            if (!Directory.Exists(savePath))
            {
                Directory.CreateDirectory(savePath);
            }

            Debug.Log("安装的路径:" + downloadPath);
            Debug.Log("保存的路径:" + savePath);
            Debug.Log("文件名:" + fileName);

            using (UnityWebRequest request = UnityWebRequest.Get(downloadPath + "/" + fileName))
            {

                if (LoadProgress != null)
                {
                    LoadProgress(request);
                }

                yield return request.SendWebRequest();

                byte[] results = request.downloadHandler.data;

                if (request.isNetworkError || request.isHttpError)
                {
                    Debug.Log("Download Error:" + request.error);
                }
                else if (request.isDone)
                {
                    Debug.Log("资源长度:" + results.Length);

                    FileInfo fileInfo = new FileInfo(savePath + "/" + fileName);
                    FileStream fs = fileInfo.Create();

                    fs.Write(results, 0, results.Length);
                    fs.Flush(); //文件写入存储到硬盘
                    fs.Close(); //关闭文件流对象
                    fs.Dispose(); //销毁文件对象
                }
            }

            Debug.Log("开始解压！");

            //开始解压
            FileStream fileStream = new FileStream(savePath + "/" + fileName, FileMode.Open);

            //       DecompressToDirectory(fileStream, savePath);

            FileInfo info = new FileInfo(savePath + "/" + fileName);
            info.Delete();


            Debug.Log("解压完成！");

            if (DownLoad != null)
                DownLoad();
        }
        #endregion

        #region test

        void TestGetFolder(string path)
        {
            //http://192.168.21.200:90/UnityAssets/CreatParty/Install
            //path = @"\\192.168.21.200\UnityAssets\CreatParty";
            path = @"//192.168.21.200/UnityAssets/CreatParty";

            /*DirectoryInfo 和Directory 查看文件夹的路径和使用UnityWebRequest下载资源的路径是不一样的！*/

            //getSourceFolder(path);

            DirectoryInfo di = new DirectoryInfo(path);
            StringBuilder sb = new StringBuilder();
            foreach (DirectoryInfo subDir in di.GetDirectories())
            {
                sb.Append(subDir.Name);
            }

            Debug.Log(sb);
        }

        #endregion
    }
}